package com.basker.pisces.orm.session;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.support.TransactionTemplate;

import com.basker.pisces.core.datasource.IDataSourceManager;
import com.basker.pisces.orm.cache.DataContractCacheManager;
import com.basker.pisces.orm.cache.DataContractLocalCacheManager;
import com.basker.pisces.orm.cache.DataContractRedisCacheManager;
import com.basker.pisces.orm.execute.ISqlExecutor;
import com.basker.pisces.spring.SpringApplicationContext;
import com.basker.pisces.tx.TransactionHelper;

/**
 * 默认的SqlSession工厂，产生的实例类型为{@link DefaultSqlSession},其事务管理器由默认的{@link IDataSourceManager}提供,目前使用的事Spring的JDBC事务管理器
 *
 * @author hangwen
 */
public class DefaultSqlSessionFactory implements ISqlSessionFactory {

    private static final Logger logger = LoggerFactory.getLogger(DefaultSqlSessionFactory.class);

    /**
     * sql执行器
     */
    @Autowired
    private ISqlExecutor sqlExecutor;

    /**
     * 数据源管理器
     */
    @Autowired
    private IDataSourceManager dataSourceManager;

    /**
     * 数据对象的缓存管理器
     *
     * @see DataContractLocalCacheManager
     * @see DataContractRedisCacheManager
     */
    @Autowired
    private DataContractCacheManager cacheManager;

    /**
     * spring事件发布器
     */
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Override
    public ISqlSession createSession() {
        return createSession("");
    }

    @Override
    public ISqlSession createSession(Isolation transactionIsolation) {
        DefaultSqlSession session = (DefaultSqlSession) createSession();

        TransactionTemplate template = this.createTransactionTemplate(transactionIsolation);
        session.setTransactionTemplate(template);

        return session;
    }

    @Override
    public ISqlSession createSession(String dataSourceName) {
        DefaultSqlSession session = new DefaultSqlSession();

        session.setDataSourceManager(this.dataSourceManager);
        session.setCacheManager(this.cacheManager);
        session.setSqlExecutor(this.sqlExecutor);
        session.setApplicationEventPublisher(this.applicationEventPublisher);
        session.setDataSourceName(dataSourceName);

        return session;
    }

    @Override
    public ISqlSession createSession(String dataSourceName, Isolation transactionIsolation) {
        DefaultSqlSession session = (DefaultSqlSession) createSession(dataSourceName);

        TransactionTemplate template = this.createTransactionTemplate(transactionIsolation);
        session.setTransactionTemplate(template);

        return session;
    }

    private TransactionTemplate createTransactionTemplate(Isolation transactionIsolation) {
        if (TransactionHelper.inTransactionScope()) {
            if (logger.isDebugEnabled()) {
                logger.debug("current thread is associated with a transaction, parameter '" + transactionIsolation
                        + "' is not effective.");
            }

            return null;
        }

        PlatformTransactionManager transactionManager = SpringApplicationContext.getInstance()
                .getBean("dynamicDataSourceTransactionManager", PlatformTransactionManager.class);

        TransactionTemplate template = new TransactionTemplate(transactionManager);
        template.setName("DefaultSqlSession's transaction definition");
        template.setIsolationLevel(transactionIsolation.value());

        return template;
    }

}
